package cards;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;

import java.awt.Insets;
import java.awt.AlphaComposite;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;

import game.CardContainer;
import game.LowerCardContainer;
import game.ServerModel;

public abstract class Card extends JComponent {

	public boolean equalsCard(Object that) {
		return equalsCard((Card) that);
	}

	public boolean equalsCard(Card that) {
		return (this.name.equalsIgnoreCase(that.name)
				&& this.number == that.number && this.color == that.color);

	}

	// TODO ********************The following three methods will decides wether
	// the player clicked on them********************************************
	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#contains(int, int)
	 */
	@Override
	public boolean contains(int arg0, int arg1) {
		return super.contains(arg0, arg1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.Component#setLocation(int, int)
	 */
	@Override
	public void setLocation(int arg0, int arg1) {
		super.setLocation(arg0, arg1);
	}

	public static int CARD_WIDTH;
	public static int CARD_HEIGHT;
	public static float ALPHA = (float) 0.3F;

	static int COLORNUMBER_X;
	static int COLORNUMBER_Y;
	static int COLORNUMBER_WIDTH;
	static int COLORNUMBER_HEIGHT;
	private static final int BUTTON_MOVE_LENGTH = 0;

	public static void initPreferredSize() {
		CARD_HEIGHT = 160;
		CARD_WIDTH = (int) (CARD_HEIGHT / 1.405);
		COLORNUMBER_X = CARD_WIDTH / 14;
		COLORNUMBER_Y = CARD_HEIGHT / 14;
		COLORNUMBER_WIDTH = 40;
		COLORNUMBER_HEIGHT = 12;
		System.out.println("COLORNUMBER_X" + COLORNUMBER_X);
		System.out.println("COLORNUMBER_Y" + COLORNUMBER_Y);

	}

	// TODO load this water print
	public static Image CardBack;
	public static Image unclickableWaterPrint;

	private CardContainer myCardContainer;

	public void linkCardContainer(CardContainer toB) {
		myCardContainer = toB;

	}

	// TODO will be called when removed from a cardContainer
	public void delink() {
		myCardContainer = null;
	}

	// http://blog.sina.com.cn/s/blog_4171e80d0100awe5.html
	public abstract Image getImage();

	// card should take charge of its own showing! it may needs to be a
	// JComponent

	// visual attributes
	// TODO all kinds of cards' paint method will adjust the way of painting
	// according to these three boolean.
	public boolean visible;
	// when the card is not clickable but is visible, use the link below
	// http://www.iteye.com/topic/309457
	public boolean clickable;
	// TODO
	public boolean clicked;// when the card is clicked, pop out a little. The
							// equipments have a different way of poping out.

	static ServerModel game;
	// game attributes
	protected String name;
	// hong tao: 1
	// fang kuai:2
	// hei tao:3
	// mei hua:4
	protected int color;
	protected int number;
	protected String description;

	// this is the upperleft stuff of the card
	// showing the color and number of the card
	protected JLabel colorNumber;
	/**
	 * only used by EquipButton
	 * @return a clone of colorNumber
	 */
	public JLabel getColorNumber(){
		JLabel toBreturn = new JLabel();
		while(colorNumber ==null){
			try {
				Thread.sleep(5);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		toBreturn.setText(colorNumber.getText());
		toBreturn.setForeground(colorNumber.getForeground());
		return toBreturn;
	}
	
	private void initColorNumber() {
		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {
				colorNumber = new JLabel();
				switch (color) {
				case 1:
					// TODO it's possible that this symbol may not show
					// correctly in
					// some context, need further testing
					colorNumber.setText("♥" + number);
					colorNumber.setForeground(Color.red);
					break;
				case 2:
					colorNumber.setText("♦" + number);
					colorNumber.setForeground(Color.red);
					break;
				case 3:
					colorNumber.setText("♠" + number);
					break;
				case 4:
					colorNumber.setText("♣" + number);
					break;
				}
				// colorNumber.move(COLORNUMBER_X, COLORNUMBER_Y);
				colorNumber.setLocation(COLORNUMBER_X, COLORNUMBER_Y);
				// colorNumber.setPreferredSize(new
				// Dimension(COLORNUMBER_WIDTH,COLORNUMBER_HEIGHT));
				colorNumber.setSize(new Dimension(COLORNUMBER_WIDTH,
						COLORNUMBER_HEIGHT));
				add(colorNumber);
				validate();
				repaint();
			}
		});
	}

	public Card(String s, int c, int n, String d) {
		// default layout is NULL
		// System.out.println("Default layout is: "+ getLayout());
		// setLayout(null);

		// visibility should be defaulty true. When using CardChoosingDialog,
		// tweak it to false;
		visible = true;
//		clicked = false;
		setClicked(false);
		clickable = false;
		name = s;
		color = c;
		number = n;
		if (color != 0 && number != 0) {
			initColorNumber();
		}
		description = d;
		setPreferredSize(new Dimension(CARD_WIDTH, CARD_HEIGHT));
		this.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				mouseClickDetected();
			}
		});
//		buffImg = new BufferedImage( Card.CARD_WIDTH, Card.CARD_HEIGHT, BufferedImage.TYPE_INT_ARGB);
	}

	public void mouseClickDetected(){
		if (clickable) {
//			clicked = !clicked;
			setClicked(!clicked);
//			if (clicked == true) {
//				moveUp();
//			} else if (clicked == false) {
//				moveDown();
//			}
			if (myCardContainer != null) {
				try {
					myCardContainer.clickUpdate(Card.this);
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
			revalidate();
			repaint();
		}
	}
	public void setColorNumber(int c, int n) {
		color = c;
		number = n;
		initColorNumber();
	}

	private void moveUp() {
		for (int m = 0; m < (2 / 3) * BUTTON_MOVE_LENGTH; m++) {
			this.setLocation(this.getLocation().x, this.getLocation().y - 1);
		}
	}

	private void moveDown() {
		for (int m = 0; m < (2 / 3) * BUTTON_MOVE_LENGTH; m++)
			this.setLocation(this.getLocation().x, this.getLocation().y + 1);
	}

	public String getName() {
		return name;
	}

	public int getColor() {
		return color;
	}

	public int getNumber() {
		return number;
	}

	public boolean checkValidCard(String s) {
		if (this.name.equalsIgnoreCase(s)) {
			return true;
		}
		return false;
	}

	public boolean checkValidColor(int c) {
		if (c == color) {
			return true;
		}
		return false;
	}

	//
	// public boolean checkValidNumber(int n) {
	// if (number == n) {
	// return true;
	// }
	// return false;
	// }

	// some cards, like BaiYinShiZi will trigger some effects when discard a
	// card.
	public void discard() {
		game.pushIntoDiscarded(this);
	}
	
	Border clickedBorder = BorderFactory.createLineBorder(Color.red);
	/**
	 * @param clicked
	 *            the clicked to set
	 */
	public void setClicked(boolean clicked) {
		this.clicked = clicked;
//		resetBorder();
		if(clicked){
			setBorder(clickedBorder);
		}else{
			setBorder(null);
		}
		revalidate();
		repaint();
	}
//   private  BufferedImage buffImg;
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		// this will paint the imageIcon
		Graphics2D g2d = (Graphics2D) g;
		// mind the sequence here
		if (!visible) {
			g2d.drawImage(Card.CardBack, 0, 0,Card.CARD_WIDTH,
					Card.CARD_HEIGHT,null);
			return;
		} else {// visible
			g2d.drawImage(getImage(),0,0,Card.CARD_WIDTH, Card.CARD_HEIGHT,
					null);
//			if (colorNumber != null) {
//				colorNumber.paintComponents(g2d);
//				System.out.println("ColorNumber is painted."+ colorNumber);
//			}
		}
//		if (clicked) {
//			g2d.setColor(Color.RED);
//			g2d.drawRect(0, 0, Card.CARD_WIDTH, Card.CARD_HEIGHT);
//		}
		if (!clickable) {
			g2d.setComposite(AlphaComposite.getInstance(
					AlphaComposite.SRC_ATOP, ALPHA));
			g2d.drawImage(unclickableWaterPrint, 0, 0, Card.CARD_WIDTH,
					Card.CARD_HEIGHT, null);
		}// if it's not clickable, it won't be clicked
			// TODO make sure that if a card is clicked, it is also
			// clickable,
			// so the player can cancel the clicked card after the second
			// click
	}
	
//	@Override
//	public void paintComponent(Graphics g) {
//		super.paintComponent(g);
//		// this will paint the imageIcon
//		Graphics2D g2d = (Graphics2D) g;
//		//buffered image for alpha
//        Graphics2D gbi = (Graphics2D) buffImg.getGraphics();
//		// mind the sequence here
//		if (!visible) {
//			gbi.drawImage(Card.CardBack, 0, 0,/* Card.CARD_WIDTH,
//					Card.CARD_HEIGHT,*/ null);
//		} else {// visible
//			gbi.drawImage(getImage(),0,0,/* Card.CARD_WIDTH, Card.CARD_HEIGHT,*/
//					null);
////			if (colorNumber != null) {
////				colorNumber.paintComponents(g2d);
////				System.out.println("ColorNumber is painted."+ colorNumber);
////			}
//		}
//		if (clicked) {
//			gbi.setColor(Color.RED);
//			gbi.drawRect(0, 0, Card.CARD_WIDTH-1, Card.CARD_HEIGHT-1);
//		}
////		if (!clickable) {
////			gbi.setComposite(AlphaComposite.getInstance(
////					AlphaComposite.SRC_ATOP, ALPHA));
////			gbi.drawImage(unclickableWaterPrint, 0, 0, Card.CARD_WIDTH,
////					Card.CARD_HEIGHT, null);
////		}// if it's not clickable, it won't be clicked
//			// TODO make sure that if a card is clicked, it is also
//			// clickable,
//			// so the player can cancel the clicked card after the second
//			// click
//		g2d.drawImage(buffImg, null, 0, 0);
//		gbi.dispose();
//	}

	public void setClickable(boolean clickable) {
		this.clickable = clickable;
		repaint();
	}

	/**
	 * @return name+"."+color+"."+number
	 */
	public String toString() {
		return name + "." + color + "." + number;
	}

	// private void setColor(int c){
	// color = c;
	// }
	// private void setNumber(int n){
	// number = n;
	// }
	public static Card createCard(String name, int c, int n) {
		Card toB = null;
		try {
			toB = (Card) Class.forName("cards." + name).newInstance();
			toB.setColorNumber(c, n);
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return toB;
	}

	// beware I implement my own instanceOf() here
	/**
	 * checking ths name(string) of the card to determine if it's certain type.
	 */
	public abstract boolean instanceOf(String superClass);
}
